package com.newfiber.business.service.impl;

import static cn.hutool.core.date.DatePattern.PURE_DATE_PATTERN;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.newfiber.business.constant.BusinessConstants;
import com.newfiber.business.domain.PatrolBasicInfo;
import com.newfiber.business.domain.PatrolLog;
import com.newfiber.business.domain.PatrolSection;
import com.newfiber.business.domain.PatrolTask;
import com.newfiber.business.domain.WorkCal;
import com.newfiber.business.domain.request.patrolPlan.PatrolPlanUserSaveRequest;
import com.newfiber.business.domain.request.patrolTask.PatrolTaskBeginRequest;
import com.newfiber.business.domain.request.patrolTask.PatrolTaskDatetime;
import com.newfiber.business.domain.request.patrolTask.PatrolTaskFinishRequest;
import com.newfiber.business.domain.request.patrolTask.PatrolTaskGeneratorDraftRequest;
import com.newfiber.business.domain.request.patrolTask.PatrolTaskQueryRequest;
import com.newfiber.business.domain.request.patrolTask.PatrolTaskSaveRequest;
import com.newfiber.business.domain.request.patrolTask.PatrolTaskStaticsRequest;
import com.newfiber.business.domain.request.patrolTask.PatrolTaskUpdateRequest;
import com.newfiber.business.domain.response.patrolHomePage.PatrolHomePageCount;
import com.newfiber.business.domain.response.patrolTask.PatrolTaskStatusStatistics;
import com.newfiber.business.enums.EPatrolPlanFixFrequencyType;
import com.newfiber.business.enums.EPatrolPlanFrequencyType;
import com.newfiber.business.enums.EPatrolRedisKey;
import com.newfiber.business.enums.EPatrolTaskSource;
import com.newfiber.business.enums.EPatrolTaskStatus;
import com.newfiber.business.mapper.PatrolTaskMapper;
import com.newfiber.business.service.IPatrolBasicInfoService;
import com.newfiber.business.service.IPatrolCaseService;
import com.newfiber.business.service.IPatrolLogService;
import com.newfiber.business.service.IPatrolPunchService;
import com.newfiber.business.service.IPatrolTaskService;
import com.newfiber.common.core.enums.EBoolean;
import com.newfiber.common.core.exception.ServiceException;
import com.newfiber.common.core.utils.CronUtils;
import com.newfiber.common.core.utils.DateUtils;
import com.newfiber.common.core.web.domain.BaseEntity;
import com.newfiber.common.core.web.service.BaseServiceImpl;
import com.newfiber.common.redis.service.RedisService;
import com.newfiber.system.api.RemoteSmsService;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 巡查任务Service业务层处理
 *
 * @author X.K
 * @date 2023-02-17
 */
@Service
public class PatrolTaskServiceImpl extends BaseServiceImpl<PatrolTaskMapper, PatrolTask> implements IPatrolTaskService {

    @Resource
    private PatrolTaskMapper patrolTaskMapper;

    @Resource
    private IPatrolBasicInfoService patrolBasicInfoService;

    @Resource
    private IPatrolLogService patrolLogService;

    @Resource
    private IPatrolCaseService patrolCaseService;

    @Resource
    private RedisService redisService;

    @Resource
    private IPatrolPunchService patrolPunchService;

    @Resource
    private RemoteSmsService remoteSmsService;

    @Override
    public long insert(PatrolTaskSaveRequest request) {
        PatrolTask patrolTask = new PatrolTask();
        BeanUtils.copyProperties(request, patrolTask);
        PatrolBasicInfo patrolBasicInfo = patrolBasicInfoService.selectDetail(request.getBasicInfoId());
        String patrolTarget = patrolBasicInfo.getPatrolTarget();
        patrolTask.setTaskName((generatorNumber(patrolTarget, NumberFormat.DateSerialNumber)));
        patrolTask.setIssuedDatetime(new Date());
        save(patrolTask);
        // 生成巡查日志
        List<PatrolTask> patrolTasks = new ArrayList<>();
        patrolTasks.add(patrolTask);
        patrolLogService.insertBatch(patrolTasks);
        return Optional.of(patrolTask).map(BaseEntity::getId).orElse(0L);
    }

    @Override
    public List<PatrolTask> insertBatch(Long planId, String status, List<PatrolTask> patrolTaskList) {
        if (CollectionUtils.isEmpty(patrolTaskList)) {
            return Collections.emptyList();
        }
        patrolTaskList.forEach(e -> e.setPlanId(planId));
        if (BusinessConstants.STATUS_0.equals(status)) {
            patrolTaskList.forEach(e -> e.setStatus(EPatrolTaskStatus.ToUse.getCode()));
        }
        saveBatch(patrolTaskList, patrolTaskList.size());
        return patrolTaskList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(String ids) {
        return deleteLogic(ids);
    }

    @Override
    public boolean beginPatrol(PatrolTaskBeginRequest request) {
        // 更新日志表开始时间
        patrolLogService.beginPatrolLog(request);

        // 更新巡查任务表任务状态
        return updateTaskStatusAndTime(request.getTaskId(), new Date(), EPatrolTaskStatus.Proceed);
    }

    @Override
    public boolean cancelPatrol(Long taskId) {
        // 更新日志表
        patrolLogService.updateCanceledTaskLog(taskId, null);

        // 删除日志对应的案件
        patrolCaseService.deleteCaseByTaskId(taskId);

        // 删除案件缓存
        redisService.deletePatternObject(EPatrolRedisKey.PatrolCase, taskId.toString());

        // 删除巡查轨迹缓存
        Long taskLogId = patrolLogService.selectLogIdByTask(taskId);
        redisService.deletePatternObject(EPatrolRedisKey.PatrolPath, taskLogId.toString());

        // 删除今日巡查
        redisService.deleteObject(EPatrolRedisKey.TodayPatrolTask, taskId.toString());

        // 删除打卡记录
        patrolPunchService.deleteByTaskId(taskId);

        // 更新巡查任务表任务状态
        return updateTaskStatusAndTime(taskId, null, EPatrolTaskStatus.ToStart);
    }

    @Override
    public boolean restartPatrol(Long taskId) {
        // 更新日志表
        patrolLogService.updateCanceledTaskLog(taskId, new Date());

        // 删除日志对应的案件
        patrolCaseService.deleteCaseByTaskId(taskId);

        // 删除巡查轨迹缓存
        Long taskLogId = patrolLogService.selectLogIdByTask(taskId);
        redisService.deletePatternObject(EPatrolRedisKey.PatrolPath, taskLogId.toString());

        // 删除打卡记录
        patrolPunchService.deleteByTaskId(taskId);

        // 删除案件缓存
        redisService.deletePatternObject(EPatrolRedisKey.PatrolCase, taskId.toString());

        return updateTaskStatusAndTime(taskId, new Date(), EPatrolTaskStatus.Proceed);
    }

    @Override
    public boolean finishPatrol(PatrolTaskFinishRequest request, PatrolSection patrolSection) {
        // 更新日志表
        patrolLogService.finishPatrolLog(request);

        // 提交巡查轨迹
        String patrolPath = patrolLogService.submitPatrolPath(request.getPatrolTaskId(), request.getPatrolLength());

        // 计算巡查覆盖率
        patrolLogService.calcPatrolCoverRate(patrolSection, request.getPatrolTaskId(), patrolPath);

        // 删除今日巡查
        redisService.deleteObject(EPatrolRedisKey.TodayPatrolTask, request.getPatrolTaskId().toString());

        // 启动临时日志的缓存案件
        Executors.newSingleThreadExecutor().submit(() -> patrolCaseService.startCachedCaseByLog(request.getPatrolLogId()));

        // 更新巡查任务
        return updateFinishedTask(request.getPatrolTaskId());
    }

    @Override
    public boolean stopPatrol(Long taskId) {
        // 停止巡查日志
        patrolLogService.stopPatrolLogBySystem(taskId);

        // 删除今日巡查
        redisService.deleteObject(EPatrolRedisKey.TodayPatrolTask, taskId.toString());

        // 更新已完成的巡查任务表任务状态
        return updateFinishedTask(taskId);
    }

    @Override
    public boolean forceCommit(PatrolTask patrolTask) {
        // 强制提交日志表
        patrolLogService.forceCommitPatrolLog(patrolTask);

        // 删除今日巡查
        redisService.deleteObject(EPatrolRedisKey.TodayPatrolTask, patrolTask.getId().toString());

        // 启动临时日志的缓存案件
        Executors.newSingleThreadExecutor().submit(() -> patrolCaseService.startCachedCaseByLog(patrolTask.getId()));

        // 更新任务状态为 已完成
        return updateFinishedTask(patrolTask.getId());
    }

    private boolean updateTaskStatusAndTime(Long taskId, Date realStartDatetime, EPatrolTaskStatus proceed) {
        UpdateWrapper<PatrolTask> patrolTask = new UpdateWrapper<PatrolTask>()
                .set("real_start_datetime", realStartDatetime)
                .set(EPatrolTaskStatus.Proceed.getCode().equals(proceed.getCode()), "expired_days", null)
                .set("status", proceed.getCode())
                .eq("id", taskId);
        return update(patrolTask);
    }

    private boolean updateFinishedTask(Long taskId) {
        PatrolTask patrolTask = new PatrolTask();
        patrolTask.setId(taskId);
        patrolTask.setRealEndDatetime(new Date());
        patrolTask.setStatus(EPatrolTaskStatus.Done.getCode());
        return updateById(patrolTask);
    }

    @Override
    public List<PatrolTask> generatorDraft(PatrolTaskGeneratorDraftRequest request) {
        if (CollectionUtils.isEmpty(request.getPatrolUserList())) {
            return Collections.emptyList();
        }

        PatrolBasicInfo patrolBasicInfo = patrolBasicInfoService.selectDetail(request.getBasicInfoId());
        List<PatrolTaskDatetime> patrolTaskDatetimeList = calcTaskDatetime(request);

        List<PatrolTask> patrolTaskList = new ArrayList<>();
        String currentDate = DateUtil.format(new Date(), PURE_DATE_PATTERN);
        int taskCount = 1;

        // 1、不平均分配，每个人都有全量任务
        if (EBoolean.False.getStringValue().equals(request.getAverageDistributeFlag())) {
            for (PatrolPlanUserSaveRequest planUser : request.getPatrolUserList()) {
                for (PatrolTaskDatetime patrolTaskDatetime : patrolTaskDatetimeList) {
                    for (int i = 0; i < patrolTaskDatetime.getCount(); i++) {
                        PatrolTask patrolTask = wrapperPatrolTask(patrolBasicInfo, currentDate,
                                taskCount, planUser, patrolTaskDatetime, request.getStatus());
                        patrolTaskList.add(patrolTask);

                        taskCount = taskCount + 1;
                    }
                }
            }
        } else {
            // 2、平均分配，每个人轮巡任务
            int patrolPlanUserIndex = 0;
            for (PatrolTaskDatetime patrolTaskDatetime : patrolTaskDatetimeList) {
                for (int i = 0; i < patrolTaskDatetime.getCount(); i++) {
                    PatrolPlanUserSaveRequest planUser = request.getPatrolUserList().get(patrolPlanUserIndex);

                    PatrolTask patrolTask = wrapperPatrolTask(patrolBasicInfo, currentDate,
                            taskCount, planUser, patrolTaskDatetime, request.getStatus());
                    patrolTaskList.add(patrolTask);

                    taskCount = taskCount + 1;

                    patrolPlanUserIndex = patrolPlanUserIndex >= request.getPatrolUserList().size() - 1 ? 0 : patrolPlanUserIndex + 1;
                }
            }
        }

        // 临时巡查人员分配巡查段
        List<PatrolTask> noSectionPatrolTaskList = patrolTaskList.stream().filter(t -> null == t.getPatrolSectionId()).collect(Collectors.toList());
        List<String> patrolSectionIdList = request.parsePatrolSectionIdList();
        if (CollectionUtils.isNotEmpty(noSectionPatrolTaskList) && CollectionUtils.isNotEmpty(patrolSectionIdList)) {
            int sectionIdIndex = 0;
            for (PatrolTask patrolTask : noSectionPatrolTaskList) {
                patrolTask.setPatrolSectionId(Long.parseLong(patrolSectionIdList.get(sectionIdIndex)));
                sectionIdIndex = sectionIdIndex >= patrolSectionIdList.size() - 1 ? 0 : sectionIdIndex + 1;
            }
        }

        return patrolTaskList;
    }

	public List<PatrolTaskDatetime> calcTaskDatetime(PatrolTaskGeneratorDraftRequest request) {
		List<PatrolTaskDatetime> taskDatetimeList = new ArrayList<>();

		EPatrolPlanFrequencyType frequencyType = EPatrolPlanFrequencyType.match(request.getPatrolFrequencyType());
		Date startDatetime = parseDatetime(request.getStartDate(), request.parseStartTime(frequencyType));
		Date endDatetime = DateUtil.offsetDay(request.getEndDate(), 1);
		List<? extends Date> dateList;

		top:
		switch (frequencyType) {
			// 固定日期
			case FixDate:
				dateList = CronUtils.getExecutionTime("0 0 " + request.getPatrolPlanFixDate().getCron(), request.getStartDate(), request.getEndDate());
				if (CollectionUtils.isEmpty(dateList)) {
					break;
				}
				for (int i = 0; i < dateList.size() - 1; i++) {
					taskDatetimeList.add(new PatrolTaskDatetime(dateList.get(i), dateList.get(i + 1)));
				}
				break;

			// 固定频率
			case FixFrequency:
				EPatrolPlanFixFrequencyType fixFrequencyType = EPatrolPlanFixFrequencyType.match(request.getPatrolPlanFixFrequency().getIntervalType());
				switch (fixFrequencyType) {
					case Day:
						dateList = DateUtil.rangeToList(startDatetime, DateUtil.offsetDay(endDatetime, -1), DateField.DAY_OF_WEEK);
						if (CollectionUtils.isEmpty(dateList)) {
							break top;
						}
						for (Date date : dateList) {
							taskDatetimeList.add(new PatrolTaskDatetime(date, parseDatetime(date,
								request.parseEndTime(frequencyType)), request.getPatrolPlanFixFrequency().getFrequency()));
						}
						break top;

					case Week:
						dateList = DateUtil.rangeToList(startDatetime, endDatetime, DateField.WEEK_OF_MONTH);
						if (CollectionUtils.isEmpty(dateList)) {
							break top;
						}
						for (int i = 0; i < dateList.size() - 1; i++) {
							taskDatetimeList.add(new PatrolTaskDatetime(dateList.get(i), parseDatetime(dateList.get(i + 1),
								request.parseEndTime(frequencyType)), request.getPatrolPlanFixFrequency().getFrequency()));
						}
						break top;

					case Month:
						dateList = DateUtil.rangeToList(startDatetime, endDatetime, DateField.MONTH);
						if (CollectionUtils.isEmpty(dateList)) {
							break top;
						}
						for (int i = 0; i < dateList.size() - 1; i++) {
							taskDatetimeList.add(new PatrolTaskDatetime(dateList.get(i), parseDatetime(dateList.get(i + 1),
								request.parseEndTime(frequencyType)), request.getPatrolPlanFixFrequency().getFrequency()));
						}
						break top;
					default:
						break top;
				}

				// 间隔日期
			case IntervalDate:
				dateList = DateUtils.rangeToList(startDatetime, endDatetime, DateField.DAY_OF_WEEK, request.getPatrolPlanIntervalDate().getInterval() + 1);
				if (CollectionUtils.isEmpty(dateList)) {
					break;
				}
				for (Date date : dateList) {
					taskDatetimeList.add(new PatrolTaskDatetime(date, parseDatetime(date, request.parseEndTime(frequencyType)), request.getPatrolPlanIntervalDate().getFrequency()));
				}
				break;

			default:
				break;
		}

		return taskDatetimeList;
	}

    @NotNull
    private PatrolTask wrapperPatrolTask(PatrolBasicInfo patrolBasicInfo, String currentDate,
                                         int taskCount, PatrolPlanUserSaveRequest planUser, PatrolTaskDatetime patrolTaskDatetime, String status) {
        PatrolTask patrolTask = new PatrolTask();
        patrolTask.setNumber("");
        patrolTask.setTaskSource(EPatrolTaskSource.Patrol.getCode());
        patrolTask.setPatrolType(patrolBasicInfo.getPatrolType());
        patrolTask.setStatus(EPatrolTaskStatus.ToStart.getCode());
        patrolTask.setBasicInfoId(patrolBasicInfo.getId());
        patrolTask.setPatrolSectionId(planUser.getSectionId());
        patrolTask.setTaskName(patrolBasicInfo.getPatrolTarget().concat(currentDate).
                concat(StrUtil.fillBefore(Integer.toString(taskCount), '0', 2)));
        patrolTask.setTaskUserId(planUser.getUserId());
        patrolTask.setPlanStartDatetime(patrolTaskDatetime.getStartDatetime());
        patrolTask.setPlanEndDatetime(patrolTaskDatetime.getEndDatetime());
        if (BusinessConstants.STATUS_1.equals(status)) {
            patrolTask.setIssuedDatetime(new Date());
        }
        return patrolTask;
    }

    @Override
    public boolean update(PatrolTaskUpdateRequest request) {
        PatrolTask patrolTask = new PatrolTask();
        BeanUtils.copyProperties(request, patrolTask);
        return updateById(patrolTask);
    }

    @Override
    public boolean startUseTask(Long planId) {
        UpdateWrapper<PatrolTask> patrolTask = new UpdateWrapper<PatrolTask>()
                .set("status", EPatrolTaskStatus.ToStart.getCode())
                .set("update_time", new Date())
                .eq("plan_id", planId)
                .eq("status", EPatrolTaskStatus.ToUse.getCode());
        return update(patrolTask);
    }

    @Override
    public boolean updateWrapper(PatrolTaskUpdateRequest request) {
        UpdateWrapper<PatrolTask> patrolTask = new UpdateWrapper<PatrolTask>()
                .set("status", EPatrolTaskStatus.Stopped.getCode())
                .set("update_time", new Date())
                .eq("plan_id", request.getPlanId())
                .ne("status", EPatrolTaskStatus.Done);
        return update(patrolTask);
    }

    private Date parseDatetime(Date date, String time) {
        return DateUtil.parseDateTime(DateUtil.formatDate(date) + " " + time);
    }

    @Override
    public long countBySection(Long patrolSectionId) {
        QueryWrapper<PatrolTask> queryWrapper = new QueryWrapper<PatrolTask>().eq("patrol_section_id", patrolSectionId);
        return count(queryWrapper);
    }

    @Override
    public long count(Long planId, EPatrolTaskStatus status) {
        QueryWrapper<PatrolTask> queryWrapper = new QueryWrapper<PatrolTask>().
                eq("plan_id", planId).
                eq("status", status.getCode());
        return count(queryWrapper);
    }

    @Override
    public long countByUser(Long taskUserId, String patrolType, EPatrolTaskStatus status) {
        QueryWrapper<PatrolTask> queryWrapper = new QueryWrapper<PatrolTask>().
                eq("task_user_id", taskUserId).
	            eq("patrol_type", patrolType).
                eq("status", status.getCode());
        return count(queryWrapper);
    }

    @Override
    public PatrolTask selectDetail(Long id) {
        PatrolTask patrolTask = selectDetailBrief(id);

        PatrolLog patrolLog = patrolLogService.selectByTask(id);
        if (null != patrolLog) {
            patrolTask.setPatrolLogId(patrolLog.getId());
            if (EPatrolTaskStatus.Proceed.getCode().equals(patrolTask.getStatus())) {
                patrolTask.setPatrolPath(patrolLogService.parseRedisPatrolPath(patrolLog.getId()));
            } else {
                patrolTask.setPatrolPath(patrolLog.getPatrolPath());
            }
        }
        return patrolTask;
    }

    @Override
    public PatrolTask selectDetailBrief(Long id) {
        PatrolTask patrolTask = patrolTaskMapper.selectOneById(id);
        if (null == patrolTask) {
            throw new ServiceException(String.format("%s ID=%s 的记录不存在", this.getClass().getSimpleName(), id));
        }
        return patrolTask;
    }

    @Override
    public List<PatrolTask> selectPage(PatrolTaskQueryRequest request) {
        return patrolTaskMapper.selectByCondition(request);
    }

    @Override
    public List<PatrolTask> selectList(PatrolTaskQueryRequest request) {
        return patrolTaskMapper.selectByCondition(request);
    }

    @Override
    public List<PatrolTask> selectList(EPatrolTaskStatus taskStatus) {
        PatrolTaskQueryRequest request = new PatrolTaskQueryRequest();
        request.setStatus(taskStatus.getCode());
        return patrolTaskMapper.selectByCondition(request);
    }

    @Override
    public List<PatrolTaskStatusStatistics> statusStatistics(PatrolTaskStaticsRequest request) {
        List<PatrolTaskStatusStatistics> statusStatistics = patrolTaskMapper.statusStatistics(request);
        for (EPatrolTaskStatus taskStatus : EPatrolTaskStatus.values()) {
            Optional<PatrolTaskStatusStatistics> optional = statusStatistics.stream().filter(t -> taskStatus.getCode().equals(t.getStatus())).findAny();
            if (optional.isPresent()) {
                optional.get().setStatusName(taskStatus.getValue());
            } else {
                statusStatistics.add(new PatrolTaskStatusStatistics(taskStatus));
            }
        }
        return statusStatistics;
    }

    @Override
    public List<PatrolTask> untilEndDateList(Date planEndDatetime, String patrolType) {
        PatrolTaskQueryRequest request = new PatrolTaskQueryRequest();
        request.setPatrolType(patrolType);
        request.setPlanEndDate(DateUtil.format(planEndDatetime, "yyyy-MM-dd"));
        return patrolTaskMapper.selectByCondition(request);
    }

    @Override
    public List<PatrolTask> selectList(List<Long> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return Collections.emptyList();
        }
        PatrolTaskQueryRequest request = new PatrolTaskQueryRequest();
        request.setIdList(idList);
        return patrolTaskMapper.selectByCondition(request);
    }

    @Override
    public List<PatrolTask> queryTodoTasks() {
        PatrolTaskQueryRequest request = new PatrolTaskQueryRequest();
        request.setStatus(EPatrolTaskStatus.ToStart.getCode());
        request.setPlanStartDatetime(DateUtil.tomorrow());
        return patrolTaskMapper.selectByCondition(request);
    }

    @Override
    public List<PatrolTask> queryAndUpdateExpiredTasks() {
        PatrolTaskQueryRequest request = new PatrolTaskQueryRequest();
        List<String> statusList = new ArrayList<>();
        statusList.add(EPatrolTaskStatus.ToStart.getCode());
        statusList.add(EPatrolTaskStatus.Expired.getCode());
        request.setStatusList(statusList);
        request.setPlanEndDatetimeEnd(new Date());
        List<PatrolTask> patrolTasks = patrolTaskMapper.selectByCondition(request);
        if (CollectionUtils.isNotEmpty(patrolTasks)) {
            for (PatrolTask patrolTask : patrolTasks) {
                patrolTask.setStatus(EPatrolTaskStatus.Expired.getCode());
                patrolTask.setExpiredDays(DateUtil.betweenDay(patrolTask.getPlanEndDatetime(), new Date(), true));
            }
            updateBatchById(patrolTasks);
        }
        return patrolTasks;
    }

    @Override
    public List<PatrolHomePageCount> patrolCount() {
        return patrolTaskMapper.patrolCount();
    }

    @Override
    public WorkCal workCal(Date startDate, Date endDate) {
        // 优先级 待完成>已超时>已完成
        SimpleDateFormat sdf = new SimpleDateFormat(DatePattern.NORM_DATE_PATTERN);

        // 找出待办to_start 任务，时间是计划开始时间
        PatrolTaskQueryRequest toDoRequest = new PatrolTaskQueryRequest();
        toDoRequest.setStatus(EPatrolTaskStatus.ToStart.getCode());
        toDoRequest.setTaskPlanStartDateFrom(startDate);
        toDoRequest.setTaskPlanStartDateTo(endDate);
        List<PatrolTask> patrolTasks = patrolTaskMapper.selectByCondition(toDoRequest);
        // 根据计划开始时间排序去重
        List<PatrolTask> patrolToDoTasks = patrolTasks.stream().sorted(Comparator.comparing(PatrolTask::getPlanStartDatetime)).collect(Collectors.toList());
        List<String> todoList = new ArrayList<>();
        patrolToDoTasks.forEach(e -> {
            todoList.add(sdf.format(e.getPlanStartDatetime()));
        });
        WorkCal workCal = new WorkCal();
        List<String> toStartList = todoList.stream().distinct().collect(Collectors.toList());
        workCal.setToStartDates(toStartList);

        // 排除有待办的日期，找出 expired proceed 的任务，时间是 计划完成时间
        PatrolTaskQueryRequest unFinishRequest = new PatrolTaskQueryRequest();
        unFinishRequest.setStatusStr("'" + EPatrolTaskStatus.Expired.getCode() + "','" + EPatrolTaskStatus.Proceed.getCode() + "'");
        unFinishRequest.setTaskPlanEndDateFrom(startDate);
        unFinishRequest.setTaskPlanEndDateTo(endDate);
        List<PatrolTask> patrolNotFinish = patrolTaskMapper.selectByCondition(unFinishRequest);
        List<PatrolTask> patrolUnFinishTasks = patrolNotFinish.stream().sorted(Comparator.comparing(PatrolTask::getPlanEndDatetime)).collect(Collectors.toList());
        List<String> unFinishList = new ArrayList<>();
        // 需要和待办的日期去重。
        patrolUnFinishTasks.forEach(e -> {
            if (!toStartList.contains(sdf.format(e.getPlanEndDatetime()))) {
                unFinishList.add(sdf.format(e.getPlanEndDatetime()));
            }
        });
        workCal.setExpireDates(unFinishList);

        // 排除待办，未完成，找出 done 的任务，时间是 实际完成实际
        PatrolTaskQueryRequest doneRequest = new PatrolTaskQueryRequest();
        doneRequest.setStatus(EPatrolTaskStatus.Done.getCode());
        doneRequest.setTaskRealEndDateFrom(startDate);
        doneRequest.setTaskRealEndDateTo(endDate);
        List<PatrolTask> patrolDone = patrolTaskMapper.selectByCondition(doneRequest);
        List<PatrolTask> patrolDoneTasks = patrolDone.stream().sorted(Comparator.comparing(PatrolTask::getRealEndDatetime)).collect(Collectors.toList());
        List<String> doneList = new ArrayList<>();
        // 需要和待办的或者正在进行中日期去重。
        patrolDoneTasks.forEach(e -> {
            if (!toStartList.contains(sdf.format(e.getRealEndDatetime())) && !unFinishList.contains(sdf.format(e.getRealEndDatetime()))) {
                doneList.add(sdf.format(e.getRealEndDatetime()));
            }
        });
        workCal.setDoneDates(doneList);
        return workCal;
    }

    @Override
    public void queryAndNoticeTodoTasks() {
        List<com.newfiber.business.domain.PatrolTask> patrolTasks = queryTodoTasks();

        // 插入数据到 通知表
        patrolTasks.forEach(e -> {
            Map<String, String> params = new HashMap<>();
            params.put("1", e.getTaskUserName());
            params.put("2", e.getTaskName());
            params.put("3", DateUtil.format(e.getPlanStartDatetime(), DatePattern.NORM_DATE_PATTERN));
            params.put("4", DateUtil.format(e.getPlanEndDatetime(), DatePattern.NORM_DATE_PATTERN));
            remoteSmsService.sendMessage("PatrolTaskToDo", JSONObject.toJSONString(params), e.getTaskUserPhone());
        });
    }

    @Override
    public void findExpiredTasks() {
        List<PatrolTask> patrolTasks = queryAndUpdateExpiredTasks();
        patrolTasks.forEach(e -> {
            Map<String, String> params = new HashMap<>();
            params.put("1", e.getTaskUserName());
            params.put("2", e.getTaskName());
            params.put("3", DateUtil.format(e.getPlanStartDatetime(), DatePattern.NORM_DATE_PATTERN));
            params.put("4", DateUtil.format(e.getPlanEndDatetime(), DatePattern.NORM_DATE_PATTERN));
            params.put("5", e.getExpiredDays().toString());
            remoteSmsService.sendMessage("PatrolTaskDelay", JSONObject.toJSONString(params), e.getTaskUserPhone());
        });
    }
}
